home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et-2_2.lha / et2.2 / applications / draw / DrawView.C < prev    next >
C/C++ Source or Header  |  1990-12-05  |  14KB  |  617 lines

  1. //$DrawView$
  2. #include "DrawView.h"
  3. #include "ObjList.h"
  4. #include "Commands.h"
  5. #include "Menu.h"
  6. #include "Document.h"
  7. #include "TextShape.h"
  8. #include "TextCmd.h"
  9. #include "Group.h"
  10. #include "CmdNo.h"
  11. #include "CollView.h"
  12. #include "ClipBoard.h"
  13. #include "System.h"
  14. #include "ImageShape.h"
  15. #include "PictureShape.h"
  16. #include "Picture.h"
  17.  
  18. const int cARRANGEMENU  = 1121,
  19.       cOPTIONEMENU  = 1122,
  20.       cGridSize     = 8;
  21.       
  22. //---- DrawView ----------------------------------------------------------------
  23.  
  24. MetaImpl(DrawView, (TP(activeTextView), TP(currShape), T(lastClick), T(grid),
  25.     TB(showGrid), TP(shapes), TP(selection), 0));
  26.  
  27. DrawView::DrawView(Document *dp, Point extent, ObjList *sl) : View(dp, extent)
  28. {
  29.     showGrid= TRUE;
  30.     grid= cGridSize;
  31.     activeText= 0;
  32.     activeTextView= 0;
  33.     lastClick = Point(100);
  34.     shapes= sl;
  35.     currShape= 0;
  36.     selection= new ObjList;
  37. }
  38.  
  39. DrawView::~DrawView()
  40. {
  41.     SafeDelete(selection);
  42.     if (shapes) {
  43.     shapes->FreeAll();
  44.     SafeDelete(shapes);
  45.     }
  46. }
  47.  
  48. //---- initializing ------------------------------------------------------------
  49.  
  50. void DrawView::SetShapes(class ObjList *sl)
  51. {
  52.     if (shapes) {
  53.     shapes->FreeAll();
  54.     SafeDelete(shapes);
  55.     }
  56.     shapes= sl;
  57.     SetSelection(0);
  58.     shapes->ForEach(Shape,SetContainer)(this);
  59.     ForceRedraw(); 
  60. }
  61.  
  62. //---- drawing -----------------------------------------------------------------
  63.  
  64. void DrawView::Invalidate(ObjList *ol)
  65. {
  66.     Rectangle bbox;
  67.     Iter next(ol);
  68.     Shape *s;
  69.     
  70.     while (s= (Shape*)next())
  71.     bbox.Merge(s->InvalRect());
  72.     InvalidateRect(bbox);
  73. }
  74.  
  75. static Bitmap *Grid= 0;
  76.  
  77. void DrawView::Draw(Rectangle r)
  78. {
  79.     RevIter previous(shapes);
  80.     register Shape *s;
  81.     
  82.     if (!gPrinting && showGrid) {
  83.     if (Grid == 0) {
  84.         Grid= new Bitmap(Point(32));
  85.         Grid->SetPixel(0, 0, 1);
  86.         Grid->SetPixel(16, 0, 1);
  87.         Grid->SetPixel(0, 16, 1);
  88.     }
  89.     GrPaintRect(r, Grid);
  90.     }
  91.  
  92.     while (s= (Shape*) previous())
  93.     s->DrawAll(r);
  94.     if (! gPrinting && selection) {
  95.     Iter next(selection);
  96.  
  97.     while (s= (Shape*)next())
  98.         if (! s->GetDeleted())
  99.         s->Highlight(On);
  100.     }
  101. }
  102.  
  103. //---- shape list management ---------------------------------------------------
  104.     
  105. void DrawView::Insert(Shape *s)
  106. {
  107.     SetSelection(0);
  108.     s->SetContainer(this);
  109.     shapes->Insert(s);
  110.     selection->Add(s);
  111.     InvalidateRect(s->InvalRect());
  112.     ShowSelection();
  113. }
  114.  
  115. void DrawView::Remove(Shape *s)
  116. {
  117.     shapes->RemovePtr(s);
  118. }
  119.  
  120. void DrawView::InsertShapes(ObjList *ol, bool tofront)
  121. {
  122.     RevIter previous(ol);
  123.     Shape *s;
  124.     
  125.     SetSelection(0);
  126.     while (s= (Shape*) previous()) {
  127.     if (! s->IsKindOf(Shape))
  128.         continue;
  129.     s->SetContainer(this);
  130.     if (tofront)
  131.         shapes->Insert(s);
  132.     else
  133.         shapes->Add(s);
  134.     selection->Add(s);
  135.     }
  136.     Invalidate(ol);
  137.     ShowSelection();
  138. }
  139.  
  140. Shape *DrawView::FindShape(Point p)
  141. {
  142.     Iter next(shapes);
  143.     Shape *s;
  144.     
  145.     while (s= (Shape*)next())
  146.     if (s->ContainsPoint1(p))
  147.         return s;
  148.     return 0;
  149. }
  150.  
  151. Shape *DrawView::FindHandle(Point p, int *nh)
  152. {
  153.     Iter next(selection);
  154.     Shape *s;
  155.     int handle;
  156.     
  157.     while (s= (Shape*)next())
  158.     if ((handle= s->PointOnHandle(p)) >= 0) {
  159.         *nh= handle;
  160.         return s;
  161.     }
  162.     return 0;
  163. }
  164.  
  165. //---- misc --------------------------------------------------------------------
  166.  
  167. void DrawView::Point2Grid(Point *np)  // constrain to viewsize and align to grid
  168. {
  169.     Point p= Min(GetExtent(), Max(gPoint3, *np));
  170.     *np= ((p+grid/2) / grid) * grid;
  171. }
  172.  
  173. void DrawView::ConstrainScroll(Point *p)
  174. {
  175.     if (activeTextView)
  176.     activeTextView->ConstrainScroll(p);
  177. }
  178.  
  179. void DrawView::RequestTool(int tix)
  180. {
  181.     Control(GetId(), 0, (void*) tix);
  182. }
  183.  
  184. void DrawView::SetTool(Object *cs)
  185. {
  186.     Shape *oldShape= currShape;
  187.  
  188.     if (cs && cs->IsKindOf(Shape))
  189.     currShape= (Shape*) cs;
  190.     else
  191.     currShape= 0;
  192.     
  193.     // enter text mode
  194.     if ((oldShape == 0 || !oldShape->IsKindOf(TextShape)) &&
  195.                 currShape && currShape->IsKindOf(TextShape)) {
  196.     PerformCommand(gResetUndo);
  197.     SetSelection(0);
  198.     }
  199.  
  200.     // leave text mode
  201.     if ((currShape == 0 || !currShape->IsKindOf(TextShape)) &&
  202.                 oldShape && oldShape->IsKindOf(TextShape)) {
  203.     PerformCommand(gResetUndo);
  204.     SetSelection(0);
  205.     SetActiveText(0);
  206.     }
  207. }
  208.  
  209. void DrawView::ShowInfo(TrackPhase tp, char *va_(fmt), ...)
  210. {
  211.     if (tp == eTrackRelease)
  212.     Control(GetId(), 123, "");
  213.     else {
  214.     char buf[100];
  215.     va_list ap;
  216.     va_start(ap, va_(fmt));
  217.     vsprintf(buf, va_(fmt), ap);
  218.     va_end(ap);
  219.     Control(GetId(), 123, buf);
  220.     }
  221. }
  222.  
  223. //---- Selection ---------------------------------------------------------------
  224.  
  225. Shape *DrawView::OneSelected()
  226. {
  227.     if (Selected() != 1)
  228.     return 0;
  229.     return (Shape*)selection->First();
  230. }
  231.  
  232. ObjList *DrawView::GetCopyOfSelection()
  233. {
  234.     //RemoveDeleted();
  235.     return (ObjList*)selection->Clone();
  236. }
  237.  
  238. ObjList *DrawView::GetDeepCopyOfSelection()
  239. {
  240.     //RemoveDeleted();
  241.     return (ObjList*)selection->DeepClone();
  242. }
  243.  
  244. ObjList *DrawView::SetSelection(ObjList *newsel)
  245. {
  246.     ObjList *oldsel= selection;
  247.     
  248.     // Reset old Selection
  249.     if (selection->Size()) {
  250.     selection->ForEach(Shape,SetSplit)(FALSE);
  251.     Invalidate(selection);
  252.     SafeDelete(selection);
  253.     selection= 0;
  254.     UpdateEvent();
  255.     }
  256.     if (newsel) {
  257.     selection= (ObjList*) newsel->Clone();
  258.     Invalidate(selection);
  259.     ShowSelection();   
  260.     } else
  261.     selection= new ObjList;
  262.     return oldsel;
  263. }
  264.  
  265. void DrawView::SetDeleted(ObjList* ol, bool b)
  266. {
  267.     ol->ForEach(Shape,SetDeleted)(b);
  268.     Invalidate(ol);
  269. }
  270.  
  271. void DrawView::RemoveDeleted()
  272. {
  273.     Iter next(shapes);
  274.     register Shape *s;
  275.  
  276.     while (s= (Shape*) next())
  277.     if (s->IsGarbage()) {
  278.         Object *tmp= shapes->Remove(s);
  279.         delete tmp;
  280.     }
  281. }
  282.  
  283. void DrawView::ShowSelection()
  284. {
  285.     Rectangle bbox= BoundingBox();
  286.     RevealRect(bbox.Expand(8), bbox.extent/3);
  287. }
  288.  
  289. void DrawView::SelectInRect(Rectangle r)
  290. {
  291.     Iter next(shapes);
  292.     register Shape *s;
  293.     
  294.     while (s= (Shape*)next())
  295.     if (!s->GetDeleted() && r.ContainsRect(s->bbox))
  296.         selection->Add(s);
  297.     Invalidate(shapes);
  298. }
  299.  
  300. Rectangle DrawView::BoundingBox()
  301. {
  302.     Rectangle bbox;
  303.     Iter next(selection);
  304.     Shape *s;
  305.     
  306.     while (s= (Shape*)next())
  307.     bbox.Merge(s->bbox);
  308.     return bbox;
  309. }
  310.  
  311. bool DrawView::HasSelection()
  312. {
  313.     return (bool) (activeTextView || selection->Size() > 0);
  314. }
  315.  
  316. //---- text --------------------------------------------------------------------
  317.  
  318. void DrawView::SetActiveText(TextShape *tp)
  319. {
  320.     if (activeText) {
  321.     selection->Remove(activeText);
  322.     //activeText->Invalidate();
  323.     activeTextView->SetNoSelection();
  324.     activeText= 0;
  325.     activeTextView= 0;
  326.     }
  327.     activeText= tp;
  328.     activeTextView= 0;
  329.     if (activeText) {
  330.     activeTextView= activeText->GetTextView();
  331.     if (! selection->ContainsPtr(activeText))
  332.         selection->Add(activeText);
  333.     //activeText->Invalidate();
  334.     //activeText->Invalidate();
  335.     }
  336.     UpdateEvent();
  337. }
  338.  
  339. //---- event handling ----------------------------------------------------------
  340.  
  341. Command *DrawView::DoLeftButtonDownCommand(Point p, Token t, int)
  342. {
  343.     Shape *ShapeUnderMouse, *s;
  344.     int handle;
  345.     SketchModes sm= eSMDefault;
  346.     bool inselection;
  347.     
  348.     if (t.Flags & eFlgShiftKey)
  349.     sm= (SketchModes)(sm | eSMSquare);
  350.     if (t.Flags & eFlgCntlKey)
  351.     sm= (SketchModes)(sm | eSMCenter);
  352.        
  353.     if (currShape == 0 || !currShape->IsKindOf(TextShape))  // exit text mode
  354.     SetActiveText(0);
  355.     
  356.     ShapeUnderMouse= FindShape(p);
  357.     lastClick= p;
  358.     
  359.     if (currShape) {    // not pointer mode
  360.     if (currShape->IsKindOf(TextShape) && ShapeUnderMouse
  361.             && ShapeUnderMouse->IsKindOf(TextShape)) {  // Text Mode
  362.         SetActiveText((TextShape*) ShapeUnderMouse);
  363.         return activeTextView->DispatchEvents(p, t, focus);
  364.     }
  365.     SetSelection(0);
  366.     return currShape->NewSketcher(this, sm);
  367.     }
  368.     
  369.     if (s= FindHandle(p, &handle))
  370.     return s->NewStretcher(this, handle);
  371.  
  372.     if (ShapeUnderMouse == 0) {
  373.     SetSelection(0);
  374.     return new ShapeSelector(this);
  375.     } 
  376.     
  377.     inselection= selection->ContainsPtr(ShapeUnderMouse);
  378.     if (! inselection) {
  379.     if (! (t.Flags & eFlgShiftKey))
  380.         SetSelection(0);
  381.     selection->Add(ShapeUnderMouse);
  382.     ShapeUnderMouse->Invalidate();
  383.     } else {
  384.     if (t.Flags & eFlgShiftKey) {
  385.         selection->Remove(ShapeUnderMouse);
  386.         ShapeUnderMouse->Invalidate();
  387.     }
  388.     }
  389.     if (selection->ContainsPtr(ShapeUnderMouse)) {
  390.     if ((handle= ShapeUnderMouse->PointOnHandle(p)) >= 0)
  391.         return ShapeUnderMouse->NewStretcher(this, handle);
  392.     return new ShapeDragger(this, ShapeUnderMouse);
  393.     }
  394.     return gNoChanges;
  395. }
  396.  
  397. Command *DrawView::DoKeyCommand(int code, Point lp, Token t)
  398. {
  399.     TextShape *ts;
  400.     
  401.     if (activeTextView)
  402.     return activeTextView->DispatchEvents(lp, t, focus);
  403.  
  404.     if (code == gBackspace)
  405.     return new SCutCopyCommand(this, cDELETE, "delete");
  406.     
  407.     //----- enter text mode and create an attached TextShape
  408.     Shape *chief= OneSelected();
  409.     RequestTool(1);
  410.     
  411.     //---- on text shape and selected hence append typed character at end
  412.     if (chief && chief->IsKindOf(TextShape)) { 
  413.     SetSelection(0);
  414.     SetActiveText((TextShape*)chief);
  415.     activeTextView->SetSelection(cMaxInt, cMaxInt);
  416.     return activeTextView->DispatchEvents(lp, t, focus);
  417.     //return activeTextView->DoKeyCommand(code, lp, t);
  418.     }
  419.     
  420.     //---- create new textshape
  421.     SetSelection(0);
  422.     ts= (TextShape*) currShape->Clone();
  423.     ts->SetContainer(this);
  424.     if (chief) {
  425.     Rectangle textRect= chief->GetTextRect();
  426.     ts->Init(textRect.NW(), textRect.SE());
  427.     ts->MakeDependentOn(chief); // make the text object dependend if there is a chief
  428.     } else
  429.     ts->Init(lastClick, lastClick);
  430.     Insert(ts);
  431.     SetActiveText(ts);
  432.     
  433.     // return activeTextView->DispatchEvents(lp, t, focus);
  434.     return activeTextView->DoKeyCommand(code, lp, t);
  435. }
  436.  
  437. Command *DrawView::DoCursorKeyCommand(EvtCursorDir cd, Point p, Token t)
  438. {
  439.     if (activeTextView)  
  440.     return activeTextView->DoCursorKeyCommand(cd, p, t);
  441.     
  442.     if (selection->Size() > 0) {
  443.     Point delta= t.CursorPoint() * grid;
  444.     Rectangle bb= BoundingBox() + delta;
  445.     delta+= bb.AmountToTranslateWithin(GetExtent());
  446.     return new CursorMoveCommand(this, delta);
  447.     }
  448.     return View::DoCursorKeyCommand(cd, p, t);
  449. }
  450.  
  451. GrCursor DrawView::GetCursor(Point lp)
  452. {
  453.     if (currShape)
  454.     return currShape->SketchCursor();
  455.     return View::GetCursor(lp);
  456. }
  457.  
  458. //---- menus -------------------------------------------------------------------
  459.  
  460. void DrawView::DoCreateMenu(Menu *menu)
  461. {
  462.     View::DoCreateMenu(menu);
  463.     Menu *m;
  464.  
  465.     menu->InsertItemsAfter(cLASTEDIT, 
  466.             "delete",       cDELETE,
  467.             "-",
  468.             "dup",          cDUP,
  469.             "edit shape",   cSPLIT,
  470.             "connect",      cCONNECT,
  471.             0);
  472.  
  473.     m= new Menu("arrange");
  474.     m->AppendItems(
  475.             "bring to front",   cTOFRONT,
  476.             "send to back",     cTOBACK,
  477.             "-",
  478.             "group",            cGROUP,
  479.             "ungroup",          cUNGROUP,
  480.             0);
  481.     menu->AppendMenu(m, cARRANGEMENU);
  482.     
  483.     m= new Menu("options");
  484.     m->AppendItems(
  485.             "grid off",     cGRID,
  486.             "hide grid       ",cSHWGRID,
  487.             0);
  488.     menu->AppendMenu(m, cOPTIONEMENU);
  489. }    
  490.  
  491. void DrawView::DoSetupMenu(Menu *menu)
  492. {
  493.     if (activeTextView) {
  494.     if (!activeTextView->Caret())
  495.         menu->EnableItem(cDELETE);
  496.     } else {
  497.     int n= selection->Size();
  498.     
  499.     if (n > 0) {
  500.         Shape *s;
  501.     
  502.         menu->EnableItems(cDELETE, cDUP, cTOFRONT, cTOBACK, cARRANGEMENU, 0);
  503.         if (s= OneSelected()) {
  504.         if (s->IsKindOf(Group))
  505.             menu->EnableItem(cUNGROUP);
  506.         if (s->CanSplit())
  507.             menu->EnableItem(cSPLIT);
  508.         } else if (n >= 2)
  509.         menu->EnableItems(cCONNECT, cGROUP, 0);
  510.     }
  511.     }
  512.     menu->ReplaceItem(cGRID, (grid == cGridSize) ? "grid off" : "grid on");
  513.     menu->ReplaceItem(cSHWGRID, showGrid ? "hide grid" : "show grid");
  514.     menu->EnableItems(cOPTIONEMENU, cGRID, cSHWGRID, 0);
  515.     View::DoSetupMenu(menu);
  516. }
  517.  
  518. Command *DrawView::DoMenuCommand(int cmd)
  519. {
  520.     Shape *p= OneSelected();
  521.  
  522.     switch(cmd) {
  523.     case cTOFRONT:
  524.     return new FrontBackCommand(this, cmd, "bring to front");
  525.  
  526.     case cTOBACK:
  527.     return new FrontBackCommand(this, cmd, "bring to back");
  528.  
  529.     case cDELETE:
  530.     if (activeTextView)
  531.         return new CutCopyCommand(activeTextView, cCUT, "delete text");
  532.     return new SCutCopyCommand(this, cmd, "delete");
  533.  
  534.     case cCUT:
  535.     case cCOPY:
  536.     gClipBoard->SetType((char*) cDocTypeET);
  537.     View::DoMenuCommand(cmd);
  538.     if (activeTextView)
  539.         return activeTextView->DoMenuCommand(cmd);
  540.     return new SCutCopyCommand(this, cmd);
  541.  
  542.     case cDUP:
  543.     return new DupCommand(this);
  544.     
  545.     case cGROUP:
  546.     return new GroupCommand(this);
  547.     
  548.     case cUNGROUP:
  549.     return new UngroupCommand(this, (Group*)p);
  550.     
  551.     case cSPLIT:
  552.     if (p)
  553.         p->SetSplit(TRUE);
  554.     break;
  555.     
  556.     case cCONNECT:
  557.     return new ConnectCommand(this);
  558.     
  559.     case cGRID:
  560.     grid= (grid == 1) ? cGridSize : 1;
  561.     break;
  562.     
  563.     case cSHWGRID:
  564.     showGrid= (bool) (! showGrid);
  565.     ForceRedraw();
  566.     break;
  567.         
  568.     default:
  569.     return View::DoMenuCommand(cmd);
  570.     }
  571.     return gNoChanges;
  572. }
  573.  
  574. //---- clipboard ----------------------------------------------------------------
  575.  
  576. void DrawView::SelectionToClipboard(char *type, ostream &os)
  577. {
  578.     if (activeTextView)
  579.     activeTextView->SelectionToClipboard(type, os);
  580.     else if (strcmp(type, cDocTypeET) == 0)
  581.     os << selection SP;
  582. }
  583.  
  584. Command *DrawView::PasteData(char *type, istream &is)
  585. {
  586.     if (activeTextView)
  587.     return activeTextView->PasteData(type, is);
  588.     
  589.     Shape *ns= 0;
  590.  
  591.     if (strcmp(type, cDocTypeET) == 0) {
  592.     Object *op;
  593.     is >> op;
  594.     if (op) {
  595.         if (op->IsKindOf(ObjList))
  596.         return new SPasteCommand(this, (ObjList*)op, lastClick);
  597.         if (op->IsKindOf(Picture))
  598.         ns= new PictureShape((Picture*)op);
  599.     }
  600.     } else if (strcmp(type, cDocTypeBitmap) == 0) {
  601.     Bitmap *bm= 0;
  602.     is >> bm;
  603.     if (bm)
  604.         ns= new ImageShape(bm);
  605.     }
  606.     if (ns)
  607.     return new SPasteCommand(this, ns, lastClick);
  608.     return gNoChanges;
  609. }
  610.  
  611. bool DrawView::CanPaste(char *type)
  612. {
  613.     if (activeTextView)
  614.     return activeTextView->CanPaste(type);
  615.     return strismember(type, cDocTypeET, cDocTypeBitmap, 0);
  616. }
  617.